﻿using CNKI.Graduate.Framework.Db;
using CNKI.Graduate.Framework.Ioc;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CNKI.Graduate.Framework.Log
{
    /// <summary>
    /// 系统日志信息管理
    /// </summary>
    [ServiceImplementation(ResolveLifetime = Lifetime.Singleton)]
    public class LogWrapper : ILogWrapper
    {
        // 保存要写入数据库的日志信息
        private readonly Queue<LogOperInfo> _queueInfo = new Queue<LogOperInfo>();

        /// <summary>
        /// 输出打印日志队列
        /// </summary>
        private readonly Queue<LogModel> _queueLogs = new Queue<LogModel>();

        // 日志列表同步锁
        private static readonly object LockHelper = new object();

        // 记录日志的线程
        private static Thread _threadLog = null;

        // 线程起止标识
        private bool _isThreadStart = false;

        public DateTime _dtLastLeaveTime = DateTime.MinValue;

        public LogWrapper()
        {
            WriteLogger.DeleteOverTimeLog();
            _isThreadStart = true;
            _threadLog = new Thread(SaveLog);
            _threadLog.IsBackground = true;
            _threadLog.Start();
        }

        private void SaveLog()
        {
            while (_isThreadStart)
            {
                #region 输出打印日志
                if (_queueLogs.Count > 0)
                {
                    LogModel logm;
                    lock (LockHelper)
                    {
                        logm = _queueLogs.Dequeue();
                    }
                    if (logm != null)
                    {
                        WriteLogger.WriteInternal(logm.Level, logm.Message, logm.ExSource);
                    }
                }
                #endregion

                #region 保存操作日志
                if (_queueInfo.Count > 0)
                {
                    LogOperInfo logInfo;

                    lock (LockHelper)
                    {
                        logInfo = _queueInfo.Dequeue();
                    }

                    if (!SaveLog(logInfo))
                    {
                        lock (LockHelper)
                        {
                            _queueInfo.Enqueue(logInfo);
                        }
                    }
                }
                #endregion

                Thread.Sleep(200);
            }
        }

        private bool SaveLog(LogOperInfo logInfo)
        {
            if (logInfo == null)
            {
                return true;
            }

            try
            {
                List<SqlParamsData> listParas = new List<SqlParamsData>();
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("user_id"), logInfo.UserId, DbType.String, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("user_name"), logInfo.UserName, DbType.String, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("ip"), logInfo.IpAddress, DbType.String, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("oper_time"), logInfo.OperTime, DbType.DateTime, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("oper_type"), logInfo.OperType, DbType.Int32, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("oper_object"), logInfo.OperObject, DbType.String, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("oper_content"), logInfo.OperContent, DbType.String, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("is_succ"), logInfo.IsSucc, DbType.Int32, ParameterDirection.Input));
                listParas.Add(new SqlParamsData(DbHelper.Db.GetSqlParamVar("app_version"), logInfo.AppVersion, DbType.String, ParameterDirection.Input));

                string strSql =
                string.Format(
                @"insert into mod_sysmgr_operlog 
                (user_id,user_name,ip,oper_time,oper_type,oper_object,oper_content,is_succ,app_version)
                values({0},{1},{2},{3},{4},{5},{6},{7},{8})",

                DbHelper.Db.GetSqlParamVar("user_id"),
                DbHelper.Db.GetSqlParamVar("user_name"),
                DbHelper.Db.GetSqlParamVar("ip"),
                DbHelper.Db.GetSqlParamVar("oper_time"),
                DbHelper.Db.GetSqlParamVar("oper_type"),
                DbHelper.Db.GetSqlParamVar("oper_object"),
                DbHelper.Db.GetSqlParamVar("oper_content"),
                DbHelper.Db.GetSqlParamVar("is_succ"),
                DbHelper.Db.GetSqlParamVar("app_version"));

                DbHelper.Db.ExecuteNonQuery(strSql, listParas.ToArray());
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }

        }
       

        #region 公共方法

        public void ThreadStop()
        {
            try
            {
                _isThreadStart = false;
                _threadLog.Abort();
                WriteLogger.WirteFile();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void Info(object message)
        {
            Info(message, null);
        }

        public void Info(object message, Exception source)
        {
            lock (LockHelper)
            {
                _queueLogs.Enqueue(new LogModel(LogLevel.Info, message, source));
            }
        }

        public void Debug(object message)
        {
            Debug(message, null);
        }

        public void Debug(object message, Exception source)
        {
            lock (LockHelper)
            {
                _queueLogs.Enqueue(new LogModel(LogLevel.Debug, message, source));
            }
        }

        public void Error(object message)
        {
            Error(message, null);
        }

        public void Error(object message, Exception source)
        {
            lock (LockHelper)
            {
                _queueLogs.Enqueue(new LogModel(LogLevel.Error, message, source));
            }
        }

        public void Warn(object message)
        {
            Warn(message, null);
        }

        public void Warn(object message, Exception source)
        {
            lock (LockHelper)
            {
                _queueLogs.Enqueue(new LogModel(LogLevel.Warn, message, source));
            }
        }

        public void SaveOperLog(LogOperInfo info)
        {
            try
            {
                lock (LockHelper)
                {
                    _queueInfo.Enqueue(info);
                }
            }
            catch (Exception ex)
            {
                Error(ex.Message);
            }
        }


     

        public void Trace(object message)
        {
            Trace(message, null);
        }

        public void Trace(object message, Exception source)
        {
            lock (LockHelper)
            {
                _queueLogs.Enqueue(new LogModel(LogLevel.Trace, message, source));
            }
        }

        public void Fatal(object message)
        {
            Fatal(message, null);
        }

        public void Fatal(object message, Exception source)
        {
            lock (LockHelper)
            {
                _queueLogs.Enqueue(new LogModel(LogLevel.Fatal, message, source));
            }
        }
        #endregion
    }
}
